import { base64, hmac, utf8 } from "./aiutil";
import { Socket } from "./node-socket";
export function generateUrl() {
    const data = generateAuth() as any;
    const arr = [];
    for (const k in data) {
        arr.push(`${k}=${data[k]}`);
    }
    const vStr = 'v3.5' //this.versionStr || `v${this.version}.1`;
    return `wss://spark-api.xf-yun.com/${vStr}/chat?${arr.join('&')}`;
}

export function generateAuth() {
    const host = 'spark-api.xf-yun.com';
    const date = new Date().toUTCString();
    return {
        host, date, authorization: authorize(host, date)
    }
}

function authorize(host, date) {
    const APISecret = process.env.AICHAT_xfAPPSECRET
    const APIKey = process.env.AICHAT_xfAPPKEY
    const tmp = `host: ${host}\ndate: ${date}\nGET /v3.5/chat HTTP/1.1`;
    const sign = hmac(utf8(APISecret), utf8(tmp));
    const authorizationOrigin = `api_key="${APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${sign}"`;
    return base64(utf8(authorizationOrigin));
}


export function chat({
    content,
    onData,
    onEnd,
}): Promise<string> {
    return new Promise(async (resolve, reject) => {

        const url = await generateUrl();

        console.log(url);

        const ws = new Socket(url);
        ws.onerror = () => {
            reject('WS_ON_ERROR');
        };
        ws.onclose = () => {
        };
        ws.onopen = () => {
            const header = {
                'app_id': process.env.AICHAT_xfAPPID,
                'uid': '1',
            };
            const chat = {
                'domain': `generalv3.5`,
                'temperature': 0.5,//this.temperature,
                'max_tokens': 1024,//this.maxTokens,
            };

            const text = [];
            text.push({ 'role': 'user', content });
            console.log('text', text);

            ws.send(JSON.stringify({
                header,
                'parameter': { chat },
                'payload': {
                    'message': {
                        // # 如果想获取结合上下文的回答，需要开发者每次将历史问答信息一起传给服务端，如下示例
                        // # 注意：text里面的所有content内容加一起的tokens需要控制在8192以内，开发者如有较长对话需求，需要适当裁剪历史信息
                        text,
                    }
                }
            }));
        };
        const answers: string[] = [];
        ws.onmessage = (e: any) => {
            const { header, payload } = JSON.parse(e.data);
            if (header.code !== 0) {
                reject('MESSAGE_ERROR:' + header.message);
                return;
            }
            // ! 当前分段的content
            const seqContent = payload.choices.text.map((item: any) => item.content).join('');
            const seq = payload.choices.seq;
            answers[seq] = seqContent;
            const end = header.status === 2;
            if (onData) onData({ content: seqContent, start: header.status === 0, end, seq });
            if (end) {
                const answerContent = answers.join('');
                const { total_tokens, question_tokens } = payload.usage.text;
                if (onEnd) onEnd({ content: answerContent, tokens: total_tokens, questionTokens: question_tokens });
                resolve(answerContent);
            }
        };
    });
}

